package middleware

import (
	"errors"
	"mcode/pkg/auth"
	"mcode/pkg/logger"
	"mcode/pkg/response"
	"mcode/pkg/utils/errorx"

	"strings"

	"github.com/gin-gonic/gin"
)

func Jwt() gin.HandlerFunc {
	return func(c *gin.Context) {
		// Get token from Authorization header
		authHeader := c.GetHeader("Authorization")
		if authHeader == "" {
			response.Unauthorized(c, "missing authorization header")
			c.Abort()
			return
		}

		// Check if the header has the Bearer prefix
		parts := strings.Split(authHeader, " ")
		if len(parts) != 2 || parts[0] != "Bearer" {
			response.Unauthorized(c, "invalid authorization header format")
			c.Abort()
			return
		}

		claims, err := auth.GetJWTManager().ValidateToken(parts[1])
		if err != nil {
			message := "invalid token"

			if errors.Is(err, auth.ErrExpiredToken) {
				message = "token has expired"
			}

			response.Unauthorized(c, message)
			c.Abort()
			return
		}

		// Store claims in context for later use
		c.Set("claims", claims)
		c.Next()
	}
}

func Rbac() gin.HandlerFunc {
	return func(c *gin.Context) {
		claims, ok := c.Get("claims")
		if !ok {
			response.Unauthorized(c, "unauthorized")
			c.Abort()
			return
		}

		authClaims, ok := claims.(*auth.Claims)
		if !ok {
			response.Unauthorized(c, "unauthorized")
			c.Abort()
			return
		}

		allowed, err := auth.GetEnforcer().HasPermission(authClaims.Role, c.Request.URL.Path, c.Request.Method)
		if err != nil {
			logger.ErrorLog("Failed to check permission",
				logger.String("role", authClaims.Role),
				logger.String("path", c.Request.URL.Path),
				logger.String("method", c.Request.Method),
				logger.ErrorField(err))
			response.ServerError(c, errorx.NewSystemError("failed to check permission"))
			c.Abort()
			return
		}

		if !allowed {
			logger.Warn("Permission denied",
				logger.String("role", authClaims.Role),
				logger.String("path", c.Request.URL.Path),
				logger.String("method", c.Request.Method))
			response.Forbidden(c, "permission denied")
			c.Abort()
			return
		}
		c.Next()
	}
}
